#pragma once

#include <AVUIGeneralTransform.h>

namespace AVUI {

/// <summary>Defines functionality that enables transformations in a 2-D plane. Transformations include rotation (<see cref="T:System.Windows.Media.RotateTransform" />), scale (<see cref="T:System.Windows.Media.ScaleTransform" />), skew (<see cref="T:System.Windows.Media.SkewTransform" />), and translation (<see cref="T:System.Windows.Media.TranslateTransform" />). This class hierarchy differs from the <see cref="T:System.Windows.Media.Matrix" /> structure because it is a class and it supports animation and enumeration semantics. </summary>
class Transform : public GeneralTransform
{
public:
    DECLARE_ELEMENT(Transform, GeneralTransform);

#pragma region Public Methods

    /// <summary>Creates a modifiable copy of this <see cref="T:System.Windows.Media.Transform" /> by making deep copies of its values. </summary>
    /// <returns>A modifiable deep copy of the current object. The <see cref="P:System.Windows.Freezable.IsFrozen" /> property of the cloned object returns false even if the <see cref="P:System.Windows.Freezable.IsFrozen" /> property of the source is true.</returns>
    TRefCountedPtr<Transform> Clone() { return (Transform*) Animatable::Clone().get_Ptr(); }

    /// <summary>Creates a modifiable clone of this <see cref="T:System.Windows.Media.Transform" /> object by making deep copies of its values. This method does not copy resource references, data bindings, or animations, although it does copy their current values. </summary>
    /// <returns>A modifiable deep copy of the current object. The <see cref="P:System.Windows.Freezable.IsFrozen" /> property of the cloned object is false even if the <see cref="P:System.Windows.Freezable.IsFrozen" /> property of the source is true.</returns>
    TRefCountedPtr<Transform> CloneCurrentValue() { return (Transform*) Animatable::CloneCurrentValue().get_Ptr(); }

    /// <summary>Transforms the specified bounding box and returns an axis-aligned bounding box that is exactly large enough to contain it.</summary>
    /// <returns>The smallest axis-aligned bounding box that can contain the transformed <paramref name="rect" />.</returns>
    /// <param name="rect">The bounding box to transform.</param>
    virtual Rect TransformBounds(Rect rect) AVUI_OVERRIDE { TransformRect(&rect); return rect; }

    /// <summary>Attempts to transform the specified point and returns a value that indicates whether the transformation was successful. </summary>
    /// <returns>true if <paramref name="inPoint" /> was transformed; otherwise, false.</returns>
    /// <param name="inPoint">The point to transform.</param>
    /// <param name="result">The result of transforming <paramref name="inPoint" />.</param>
    virtual bool TryTransform(const Point& inPoint, Point* pResult) AVUI_OVERRIDE { *pResult = get_Value().Transform(inPoint); return true; }

#pragma endregion Public Methods

#pragma region Public Properties

    /// <summary>Gets an identity transform. </summary>
    /// <returns>An identity transform.</returns>
    static Transform* get_Identity();

    /// <summary>Gets the inverse of this transform, if it exists.</summary>
    /// <returns>The inverse of this transform, if it exists; otherwise, null.</returns>
    virtual TRefCountedPtr<GeneralTransform> get_Inverse() AVUI_OVERRIDE;

    /// <summary>Gets the current transformation as a <see cref="T:System.Windows.Media.Matrix" /> object. </summary>
    /// <returns>The current matrix transformation.</returns>
    virtual Matrix get_Value() = 0;

#pragma endregion Public Properties

public:

#pragma region Internal Methods

    static void GetTransformValue(Transform* pTransform, Matrix* pCurrentTransformValue);
    virtual void MultiplyValueByMatrix(Matrix* pResult, const Matrix& matrixToMultiplyBy);
    virtual void TransformRect(Rect* pRect);

#pragma endregion Internal Methods

#pragma region Internal Properties

    virtual TRefCountedPtr<Transform> get_AffineTransform() AVUI_OVERRIDE { return this; }
    virtual bool get_IsIdentity() = 0;

#pragma endregion Internal Properties

private:

#pragma region Private Statics

static TRefCountedPtr<Transform> s_identity;

#pragma endregion Private Statics
};


}; // namespace AVUI
